package com.wz.jaav.classreader.classFile;

import com.wz.jaav.classreader.ClassReader;
import com.wz.jaav.classreader.classFile.constant.*;
import com.wz.jaav.util.CommonUtils;

import java.util.Arrays;

public class ConstantPool {
    private short count;
    private short totalConstantInfo;
    private ConstantInfo[] infos;

    public void build(ClassReader cr){
        totalConstantInfo = CommonUtils.byteToShort(cr.doRead(2));
        infos = new ConstantInfo[totalConstantInfo];
        for (int i = 0; i< totalConstantInfo ; i++){
            if (i == 0){
                infos[0] = new ConstantNull();
            } else{
                buildInfos(cr);
            }
            count ++;
        }
    }

    private void buildInfos(ClassReader cr){
        byte tag = cr.doRead(1)[0];
        if (tag == ConstantMethodref.TAG_METHOD_REF){
            short classInfoIndex = CommonUtils.byteToShort(cr.doRead(2));
            short nameAndTypeIndex = CommonUtils.byteToShort(cr.doRead(2));
            ConstantMethodref constantMethodref = new ConstantMethodref(classInfoIndex, nameAndTypeIndex);
            infos[count] = constantMethodref;
        } else if (tag == ConstantString.TAG_STRING_INFO){
            short stringIndex = CommonUtils.byteToShort(cr.doRead(2));
            ConstantString constantString = new ConstantString(stringIndex);
            infos[count] = constantString;
        } else if (tag == ConstantFieldref.TAG_FEILD_REF){
            short classInfoIndex = CommonUtils.byteToShort(cr.doRead(2));
            short nameAndTypeIndex = CommonUtils.byteToShort(cr.doRead(2));
            ConstantFieldref constantFieldref = new ConstantFieldref(classInfoIndex, nameAndTypeIndex);
            infos[count] = constantFieldref;
        } else if (tag == ConstantClass.TAG_CLASS_INFO){
            short classStringIndex = CommonUtils.byteToShort(cr.doRead(2));
            ConstantClass constantClass = new ConstantClass(classStringIndex);
            infos[count] = constantClass;
        } else if (tag == ConstantUtf8.TAG_UTF_8){
            short length = CommonUtils.byteToShort(cr.doRead(2));
            byte[] str = cr.doRead(length);
            ConstantUtf8 constantUtf8 = new ConstantUtf8(length, str);
            infos[count] = constantUtf8;
        } else if (tag == ConstantNameAndType.TAG_NAME_AND_TYPE){
            short nameIndex = CommonUtils.byteToShort(cr.doRead(2));
            short nameDesIndex = CommonUtils.byteToShort(cr.doRead(2));
            ConstantNameAndType nameAndType = new ConstantNameAndType(nameIndex, nameDesIndex);
            infos[count] = nameAndType;
        } else {
            System.out.println("tag:" + tag + "丢弃!");
        }
    }

    public short getTotalConstantInfo() {
        return totalConstantInfo;
    }

    public ConstantInfo getById(short id){
        for (int i = 0; i< infos.length; i++){
            if (id == i){
              return infos[i];
            }
        }
        return null;
    }

    @Override
    public String toString() {
        return "ConstantPool{" +
                "totalConstantInfo=" + totalConstantInfo +
                ", infos=" + printInfos() +
                '}';
    }

    public String printInfos(){
        System.out.println("total:" + totalConstantInfo);
        StringBuffer sb = new StringBuffer();
        for(int i=0 ; i< infos.length;i++){
            if (infos[i] != null){
                sb.append("id:").append(i).append("--").append(infos[i].toString());
                if (infos[i] instanceof ConstantInfo){
                    System.out.println("    cosId:"+ i + "--" + infos[i].toString());
                } else{
                    System.out.println("id:"+ i + "--" + infos[i].toString());
                }
            }
        }
        return sb.toString();
    }
}